/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dipl.algorithm.math.utility;

import java.math.BigInteger;
import org.apfloat.Apfloat;

/**
 * Class with functions and constants based on arbitrary precision numbers.
 * Arbitrary precisision will only work if Ring-operations(+,-,*) are used on
 * Apfloats.
 */
public class ApfloatUtils {

	//
	// STATIC MEMBERS
	//
	
	/**
	 * Globally used radix
	 */
	public static final int radix = 2;

	/**
	 * constant zero in global radix
	 */
	public static final Apfloat _0 = Apfloat.ZERO.toRadix( radix );

	/**
	 * constant one in global radix
	 */
	public static final Apfloat _1 = Apfloat.ONE.toRadix( radix );

	// PUBLIC METHODS

	/**
	 * Creates copy of given <code>Apfloat</code>.
	 * @param x
	 * @return
	 */
	public static Apfloat CopyOf( Apfloat x ) {
		return x.add( Apfloat.ZERO );
	}

	/**
	 * Calculates binomial coefficient (n k) assuming n,k being integers
	 * @param n
	 * @param k
	 * @param _1_ constant 1 (must have finite precision)!
	 * @param _0_ constant 0 (must have finite precision)!
	 * @return
	 */
	public static Apfloat BinomialCoefficient( Apfloat n, Apfloat k, Apfloat _1_, Apfloat _0_ ) {
		if( k.compareTo( _0_ ) == 0 )
			return _0_;
		if( k.add( k ).compareTo( n ) > 0 ) { // 2k > n?
			return BinomialCoefficient( n, n.subtract( k ), _1_, _0_ );
		}
		Apfloat res = n;
		Apfloat i = _1_.add( _1_ );
		Apfloat np1 = n.add( _1_ );
		while( i.compareTo( k ) <= 0 ) {
			res = res.multiply( np1.subtract( i ) );
			res = res.divide( i );
			i = i.add( _1_ );
		}
		return res;
	}

	/**
	 * Returns max(a,b)
	 * @param a
	 * @param b
	 * @return
	 */
	public static Apfloat Max( Apfloat a, Apfloat b ) {
		return (a.compareTo( b ) >= 0 ? a : b );
	}

	/**
	 * Returns min(a,b)
	 * @param a
	 * @param b
	 * @return
	 */
	public static Apfloat Min( Apfloat a, Apfloat b ) {
		return (a.compareTo( b ) <= 0 ? a : b );
	}

	public static Apfloat ValueOf( BigInteger x ) {
		return new Apfloat( x, Apfloat.INFINITE, radix );
	}

	public static Apfloat ValueOf( double x ) {
		return new Apfloat( x, Apfloat.INFINITE, radix );
	}

	public static Apfloat ValueOf( float x ) {
		return new Apfloat( x, Apfloat.INFINITE, radix );
	}

	public static Apfloat ValueOf( int x ) {
		return new Apfloat( x, Apfloat.INFINITE, radix );
	}

	public static Apfloat ValueOf( long x ) {
		return new Apfloat( x, Apfloat.INFINITE, radix );
	}
}
